/**
 * 
 */
package com.rrd.hive.udf;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.hadoop.hive.ql.exec.UDF;


/**
 * 实现excel内部函数IRR，需要传入2个或3个参数：
 * 参数1：期号
 * 参数2：金额
 * 参数3：进件金额
 * 参数4：
 * @author liubaoxin
 *
 */
public class ExcelIRRUDAF extends UDF {
	 private Map<Integer,Double> map = new HashMap<Integer,Double>(30);
	 private String[] arr = null;
	public Double evaluate(List<String> list, double loanAmt) {
	
	 return evaluate(list,loanAmt, 0.1D);
	}
	/**
	 * 
	 * @param list，集合元素结构：(期数,金额),期数主要用于排序
	 * @param loanAmt
	 * @param guess
	 * @return
	 */
	public Double evaluate(List<String> list, double loanAmt, double guess) {
		 map.clear();
		 if(list==null || list.size()<=0){
		 	return null;
		 }
		 for(String s:list){
			 arr = s.split(",");
			 map.put(Integer.parseInt(arr[0]), Double.parseDouble(arr[1]));
		 }
		 double[] values=new double[list.size()+1];
		 values[0]=0-loanAmt;
		 for(int i=0;i<list.size();i++){
			 
			 if(map.get(0)==null && map.get(i+1)!=null) {
				 values[i+1]=map.get(i+1);
			 }else if(map.get(i)==null){
			 	continue;
			 } else{
				 values[i+1]=map.get(i);
			 }
		 }
		 double d = irr(values,guess);
		 return d;
	}
	public static double irr(double[] values, double guess) {
		int maxIterationCount = 20;
		double absoluteAccuracy = 1.0E-007D;

		double x0 = guess;

		int i = 0;
		while (i < maxIterationCount) {
			double fValue = 0.0D;
			double fDerivative = 0.0D;
			for (int k = 0; k < values.length; k++) {
				fValue += values[k] / Math.pow(1.0D + x0, k);
				fDerivative += -k * values[k] / Math.pow(1.0D + x0, k + 1);
			}
			double x1 = x0 - fValue / fDerivative;
			if (Math.abs(x1 - x0) <= absoluteAccuracy) {
				return x1;
			}
			x0 = x1;
			i++;
		}
		return (0.0D / 0.0D);
	}
	
	 public static void main(String[] args) {
		 ExcelIRRUDAF irr = new ExcelIRRUDAF();
		 List<String> list = new ArrayList<String>();
		 list.add("20191005,501");
		 double loanAmt=950;
		 double ir=irr.evaluate(list, loanAmt);
		 System.out.println("irr="+ir);
	}
}
